package birdsong.comm.implemented;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import birdsong.comm.ServerSideMessage;

public class ServerComm implements birdsong.comm.ServerComm {

	
	
	private HashMap<String, ClientHandler> clientHandlers = new HashMap<String, ClientHandler>();
	//Mensagens pendentes para entrega ao servidor//outro grupo 
	private BlockingQueue<ServerSideMessage> pendingMessages = new LinkedBlockingQueue<ServerSideMessage>();
	
	
	
	private final int PORT=8089;
	private final String IPBIND="127.0.0.1";
	
	private ServerSocket serverSocket;
	
	
	@Override
	public void start() {
	
		System.out.println("A iniciar servidor.....");
		try {

			serverSocket= new ServerSocket(PORT);
			System.out.println("Servidor iniciado no em:" + serverSocket.getInetAddress() +":"+PORT);
		//	serverSocket.bind(new InetSocketAddress("172.17.4.103", PORT));
			
		} catch (IOException e) {
			System.out.println("Erro ao iniciar o servidor....");
			e.printStackTrace();
		}
		SocketListener l = new SocketListener(serverSocket, this);
		Thread t = new Thread(l);
		t.start();
		
	}

	@Override
	public ServerSideMessage getNextMessage() {
			try {
				return pendingMessages.take();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
	}

	@Override
	public synchronized boolean hasNextMessage() {
		return !pendingMessages.isEmpty();
	}

	@Override
	public void sendBirdsongMessage(String fromNickname, String toNickname, String birdsongMessage) {
		ClientSideMessage message = 
			new ClientSideMessage(birdsongMessage, fromNickname, birdsong.comm.ClientSideMessage.Type.BIRDSONG_MESSAGE);
		if(clientHandlers.get(toNickname) != null){
			clientHandlers.get(toNickname).sendMessage(message);
		}
	}

	@Override
	public void sendNewFollower(String toNickname, String newFollower) {
		ClientSideMessage message = 
			new ClientSideMessage(newFollower, birdsong.comm.ClientSideMessage.SERVER, birdsong.comm.ClientSideMessage.Type.FOLLOWER);
		if(clientHandlers.get(toNickname) != null){
			clientHandlers.get(toNickname).sendMessage(message);
		}

	}

	@Override
	public void sendNewUnfollow(String toNickname, String unfollower) {
		ClientSideMessage message = 
			new ClientSideMessage(unfollower, birdsong.comm.ClientSideMessage.SERVER, birdsong.comm.ClientSideMessage.Type.UNFOLLOWER);
		if(clientHandlers.get(toNickname) != null){
			clientHandlers.get(toNickname).sendMessage(message);
		}
	}

	@Override
	public void sendError(String toNickname, String error) {
		ClientSideMessage message = 
			new ClientSideMessage(error, birdsong.comm.ClientSideMessage.SERVER, birdsong.comm.ClientSideMessage.Type.ERROR);
		if(clientHandlers.get(toNickname) != null){
			clientHandlers.get(toNickname).sendMessage(message);
		}
	}

	@Override
	public void sendClientConnected(String toNickname, String connectedNickname) {
		ClientSideMessage message = 
			new ClientSideMessage(connectedNickname, birdsong.comm.ClientSideMessage.SERVER, birdsong.comm.ClientSideMessage.Type.CONNECTED);
		if(clientHandlers.get(toNickname) != null){
			clientHandlers.get(toNickname).sendMessage(message);
		}
	}

	@Override
	public void sendClientDisconnected(String toNickname, String disconnectedNickname) {
		ClientSideMessage message = 
			new ClientSideMessage(disconnectedNickname, birdsong.comm.ClientSideMessage.SERVER, birdsong.comm.ClientSideMessage.Type.DISCONNECTED);
		if(clientHandlers.get(toNickname) != null){
			clientHandlers.get(toNickname).sendMessage(message);
		}
	}

	@Override
	public boolean clientIsConnected(String nickname) {
		if(clientHandlers.get(nickname) == null){
			return false;
		}
		return true;
	}

	@Override
	public synchronized void disconnectClient(String nickname) {
		clientHandlers.get(nickname).disconnect();
		clientHandlers.remove(nickname);
	}
	
	
	public synchronized void receiveMessageFromClient(birdsong.comm.implemented.ServerSideMessage objectReceived) {
			try {
				pendingMessages.put(objectReceived);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
	}
	
	public void updateHandlerOwner(String owner, ClientHandler handler){
		clientHandlers.put(owner, handler);
	}

	
	
	
	private class SocketListener implements Runnable{
		
		ServerSocket serverSocket;
		ServerComm comm;
		private boolean error=false;
		
		public SocketListener(ServerSocket serverSocket, ServerComm serverComm) {
			this.serverSocket=serverSocket;
			this.comm=serverComm;
		}

		@Override
		public void run() {
			
			while (!error){
				try {
					Socket s = serverSocket.accept();
					ClientHandler handler = new ClientHandler(s,comm);					
					handler.start();
					
				} catch (IOException e) {
					error=true;
					//e.printStackTrace();
					
				}
			}
			
		}
		
	}


	public synchronized void disconnectClientForced(String clientNickName) {
		disconnectClient(clientNickName);

	}
	
	public void terminate(){
		try {
			serverSocket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}
